﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using HostConfig;

namespace TaskScheduling
{
    public class Scheduler
    {
        private TaskElement taskConfig;
        private bool token;

        public bool Token
        {
            get { return token; }
        }

        public TaskElement TaskConfig
        {
            get { return taskConfig; }
            set { taskConfig = value; }
        }

        public Scheduler(TaskElement taskConfig)
        {
            this.taskConfig = taskConfig;
        }

        public void Schedule()
        {
            while (true)
            {
                Thread.Sleep(5000);
                token = Schedule(this.taskConfig, DateTime.Now);
            }
        }

        private bool Schedule(TaskElement taskConfig, DateTime now)
        {
            while (true)
            {
                Thread.Sleep(1000);
                if (!string.IsNullOrEmpty(taskConfig.CfgFile))
                {
                    try
                    {
                        ITask.TaskConfig config = ITask.TaskConfig.Deserialize(taskConfig.CfgFile);

                        DateTime lastRunTime;
                        if (!DateTime.TryParse(config.Savings.LastRunTime, out lastRunTime))
                        {
                            lastRunTime = DateTime.MinValue;
                        }

                        #region StopOnBusy
                        bool stopOnBusy = taskConfig.StopOnBusy;
                        if (stopOnBusy && !string.IsNullOrEmpty(taskConfig.BusyTimeInDay))
                        {
                            List<BusyTime> busyTimeList = new List<BusyTime>();
                            string[] busyTimes = taskConfig.BusyTimeInDay.Split(new char[] { ',' });
                            if (busyTimes.Length > 0)
                            {
                                foreach (string bt in busyTimes)
                                {
                                    string[] times = bt.Split(new char[] { '|' });
                                    DateTime timeBegin;
                                    DateTime timeEnd;
                                    if (DateTime.TryParse(times[0].Trim(), out timeBegin) && DateTime.TryParse(times[1].Trim(), out timeEnd))
                                    {
                                        if (timeBegin <= timeEnd)
                                        {
                                            BusyTime busyTime = new BusyTime();
                                            busyTime.Begin = now.Date + timeBegin.TimeOfDay;
                                            busyTime.End = now.Date + timeBegin.TimeOfDay;
                                            busyTimeList.Add(busyTime);
                                        }
                                        else
                                        {
                                            BusyTime busyTime1 = new BusyTime();
                                            busyTime1.Begin = now.Date;
                                            busyTime1.End = now.Date + timeBegin.TimeOfDay;
                                            busyTimeList.Add(busyTime1);
                                            BusyTime busyTime2 = new BusyTime();
                                            busyTime2.Begin = now.Date + timeEnd.TimeOfDay;
                                            busyTime2.End = now.Date.AddDays(1);
                                            busyTimeList.Add(busyTime2);
                                        }
                                    }
                                }
                            }
                            if (busyTimeList.Count > 0)
                            {
                                foreach (BusyTime busyTime in busyTimeList)
                                {
                                    if (busyTime.Begin <= now && busyTime.End >= now)
                                    {
                                        return false;
                                    }
                                }
                            }
                        }
                        #endregion

                        #region RunTime
                        if (taskConfig.RunType == RunType.Periodically)
                        {
                            if (taskConfig.RunTime.Length > 0)
                            {
                                string[] runTimes = taskConfig.RunTime.Split(new char[] { ',' });
                                List<DateTime> runTimeList = new List<DateTime>();
                                foreach (string runTime in runTimes)
                                {
                                    DateTime dt;
                                    if (DateTime.TryParse(runTime, out dt))
                                    {
                                        runTimeList.Add(dt);
                                    }
                                }
                                foreach (DateTime runTime in runTimeList)
                                {
                                    if (lastRunTime < runTime && now >= runTime)
                                    {
                                        if (taskConfig.IfWeekly)
                                        {
                                            string[] daysInWeek = taskConfig.DaysInWeek.Split(new char[] { ',' });
                                            if (daysInWeek.Length > 0)
                                            {
                                                foreach (string day in daysInWeek)
                                                {
                                                    int d;
                                                    if (int.TryParse(day, out d))
                                                    {
                                                        if (d == (int)now.DayOfWeek)
                                                        {
                                                            return true;
                                                        }
                                                    }
                                                }
                                                return false;
                                            }
                                        }
                                        else
                                        {
                                            return true;
                                        }
                                    }
                                }
                                return false;
                            }
                            else
                            {
                                return false;
                            }
                        }
                        else if (taskConfig.RunType == RunType.Circularly)
                        {
                            int cycle;
                            if (int.TryParse(taskConfig.Cycle, out cycle))
                            {
                                if (((TimeSpan)(now - lastRunTime)).Seconds >= cycle)
                                {
                                    return true;
                                }
                                else
                                {
                                    return false;
                                }
                            }
                            else
                            {
                                return false;
                            }
                        }
                        else if (taskConfig.RunType == RunType.Preset)
                        {
                            DateTime time;
                            if (DateTime.TryParse(taskConfig.RunTime, out time))
                            {
                                if (now >= time)
                                {
                                    return true;
                                }
                                else
                                {
                                    return false;
                                }
                            }
                            else
                            {
                                return false;
                            }
                        }
                        else
                        {
                            return false;
                        }
                        #endregion

                    }
                    catch (Exception ex)
                    {
                        return false;
                    }
                }
            }
        }
    }
}
